package fr.mywiki.view.web.struts.form.entry;


import java.rmi.RemoteException;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
import java.util.TreeMap;

import javax.ejb.FinderException;
import javax.servlet.http.HttpServletRequest;

import org.jdom.JDOMException;

import fr.mywiki.business.entry.EntryAccessManager;
import fr.mywiki.business.entry.EntryLite;
import fr.mywiki.business.entry.LockManager;
import fr.mywiki.business.entry.meta.EntryModel;
import fr.mywiki.business.entry.meta.EntryModelManager;
import fr.mywiki.business.entry.meta.ModelException;
import fr.mywiki.business.entry.meta.Property;
import fr.mywiki.business.login.LoginManager;
import fr.mywiki.business.resources.ResourceManager;
import fr.mywiki.business.structure.StructureLite;
import fr.mywiki.business.versioning.VersionLite;
import fr.mywiki.business.versioning.VersionManager;
import fr.mywiki.view.web.struts.form.file.ManageFileForm;
import fr.mywiki.view.web.struts.form.structure.SelectMultiStructController;
import fr.mywiki.view.web.struts.form.structure.SelectMultiStructure;

/**
 * The Action Form corresponding to the edition of an entry.
 * 
 * @author tlombard
 */
public class EditEntryForm extends ManageFileForm implements SelectMultiStructure {

	private static final long serialVersionUID = 1L;

	/* The different modes of utilization of this formular. */
	/** Creation mode */
	public static final String MODE_CREATION = "mode_creation";
	/** Edition mode */
	public static final String MODE_EDITION = "mode_edition";
	
	/* Specific messages to display concerning the rights */
	/** Empty set of consulting structures */
	public static final String CONSULTATION_RIGHTS_EMPTY = "entry.access.consultation.empty";
	/** Not empty set of consulting structures */
	public static final String CONSULTATION_RIGHTS_LIST = "entry.access.consultation";
	/** Empty set of editing structures */
	public static final String EDITION_RIGHTS_EMPTY = "entry.access.edition.empty";
	/** Not empty set of editing structures */
	public static final String EDITION_RIGHTS_LIST = "entry.access.edition";
	
	/* The sets of structures managed in this form */
	public static final String CONSULTATION_RIGHTS = "consultationRights";
	public static final String EDITION_RIGHTS = "editionRights";
	
	/** If the current mode is edition, then the entry id is known. */
	private Long entryId;
	
	/** The title of the entry */
	private String title;
	
	/** The chosen model for this entry */
	private EntryModel selectedModel;
	
	/** Property values for the currently selected model. */
	private TreeMap propValues;
	
	/** The identifier of the model selected by the user. */
	private Long selectedModelId;
	
	/** All the models among which the user can choose for this entry. */
	private Collection selectableModels;
	
	/**
	 * Should we display a message telling the user he is not editing the latest
	 * version ?
	 */
	private boolean displayMessage;
	
	/**
	 * The mode describes the way of use for this edition : edition of an existing entry or
	 * creation of a new one.
	 */
	private String mode;
	
	/**
	 * The controller which enables the selection of the visibility structures.
	 */
	private SelectMultiStructController controller;
	
	/** A <code>Set</code> of <code>StructureLite</code>, the structures that can consult the entry. */
	private Set consultationStructures;
	
	/** A <code>Set</code> of <code>StructureLite</code>, the structures that can edit the entry. */
	private Set editionStructures;
	
	/** What set of structures are we currently editing ? */
	private String structuresSet = null;
	
	/** What do we display concerning the consultation rights. */
	private String consultationRights;
	
	/** What do we display concerning the edition rights. */
	private String editionRights;
	
	/** Who can manage view and edit rights ? */
	private boolean canSetRights;
  
  /** Is the entry locked in edition ? */
  private boolean isLocked;
  
  /** The lock time */
  private String lockTime;
  
  /** Is the current user allowed to manage files */
  private boolean manageFiles;
  
	/** Resets the formular with empty values. */
	private void reset() throws RemoteException {
		title = null;
		displayMessage = false;
		
		consultationStructures = new HashSet();
		editionStructures = new HashSet();
    
		isLocked = false;
    
    selectedModel = null;
    selectedModelId = null;
    selectableModels = EntryModelManager.findAllModels();
    
    manageFiles = false;
	}
	
	/**
	 * Initializes this formular with the given version (edition mode).
	 * 
	 * @param version
	 *          the <code>VersionLite</code> object to be edited.
	 * @param request
	 *          the request.
	 */
	public void initEdition(VersionLite version, HttpServletRequest request)
			throws RemoteException, FinderException, SQLException, ParseException,
			ModelException, JDOMException {
		reset();
		mode = MODE_EDITION;
		EntryLite entry = VersionManager.getInstance().getEntry(version);
		title = entry.getTitle();
		entryId = entry.getId();
		displayMessage = !VersionManager.getInstance().isCurrentVersion(version);
		
		consultationStructures = EntryAccessManager.getConsultStructures(entry);
    setConsultationRights(getConsultationRightsString(ResourceManager.getLocale(request)));
		editionStructures = EntryAccessManager.getEditionStructures(entry);
    setEditionRights(getEditionRightsString(ResourceManager.getLocale(request)));
		
		setSelectMultiStructureController(SelectMultiStructController
				.createController(new HashSet(),
						request));
		
		// It it possible to manage rights only if the user is connected
		canSetRights = EntryAccessManager.MANAGE_ENTRIES_ACCESS
				&& LoginManager.getLoggedUser(request.getSession()) != null;
    
    // Is the entry locked ? Computing the lock time
    isLocked = LockManager.isLocked(entry);
    lockTime = Long.toString(LockManager.lockTime);
    
    // Which model ?
    selectedModel = EntryModelManager.getModel(entry);
    selectedModelId = selectedModel.getId();
    initPropValues();
	}
	
	/**
	 * Initializes the formular in creation mode.
	 * 
	 * @param title
	 *          the title of the entry to create (not null).
	 * @param request
	 *          the request.
	 */
	public void initCreation(String title, HttpServletRequest request)
			throws RemoteException, FinderException, SQLException, ModelException,
			JDOMException {
		reset();
		this.title = title;
		mode = MODE_CREATION;
		
		setSelectMultiStructureController(SelectMultiStructController
				.createController(new HashSet(), request));
		
		setConsultationRights(getConsultationRightsString(ResourceManager
				.getLocale(request)));
		setEditionRights(getEditionRightsString(ResourceManager
				.getLocale(request)));
		
		// It it possible to manage rights only if the user is connected
		canSetRights = EntryAccessManager.MANAGE_ENTRIES_ACCESS
				&& LoginManager.getLoggedUser(request.getSession()) != null;
		
		// Which model ? default one
		selectedModel = EntryModelManager.getDefaultEntryModel();
		selectedModelId = selectedModel.getId();
		initPropValues();
	}
	
	/**
	 * Fills the property values for the selected model.
	 */
	private void initPropValues() {
		propValues = new TreeMap();
		EntryModel model = getSelectedModel();
		Iterator itProps = model.iterateProperties();
		while(itProps.hasNext()) {
			Property prop = (Property) itProps.next();
			propValues.put(prop.getName(), prop);
		}
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getMode() {
		return mode;
	}

	public Long getEntryId() {
		return entryId;
	}

	public void setEntryId(Long entryId) {
		this.entryId = entryId;
	}

	public boolean isDisplayMessage() {
		return displayMessage;
	}

	public void setDisplayMessage(boolean displayMessage) {
		this.displayMessage = displayMessage;
	}

	public SelectMultiStructController getSelectMultiStructureController() {
		return controller;
	}

	public void setSelectMultiStructureController(SelectMultiStructController controller) {
		this.controller = controller;
	}

	public Long getIdStructure() {
		return controller.getIdFocus();
	}

	public void setIdStructure(Long idStructure) {
		try {
			controller.setIdFocus(idStructure);
		} catch (RemoteException e) {
		}
	}

	public String getConsultationRights() {
		return consultationRights;
	}

	public void setConsultationRights(String consultationRights) {
		this.consultationRights = consultationRights;
	}
	
	/** Updates the string consultationRights String from the locale. */
	public String getConsultationRightsString(Locale locale)
			throws RemoteException, FinderException {
		Set rights = consultationStructures;
		if(rights.isEmpty())
			return ResourceManager.getMessage(CONSULTATION_RIGHTS_EMPTY,
					locale);
		
		StringBuffer buf = new StringBuffer(ResourceManager.getMessage(
				CONSULTATION_RIGHTS_LIST, locale));
		
		Iterator itStruct = rights.iterator();
		while(itStruct.hasNext()) {
			StructureLite struct = (StructureLite)itStruct.next();
			buf.append(struct.getFullName());
			if(itStruct.hasNext())
				buf.append(", ");
		}
		
		return buf.toString();
	}
	
	/** Updates the string editionRights String from the locale. */
	public String getEditionRightsString(Locale locale)
			throws RemoteException, FinderException {
		Set rights = editionStructures;
		if(rights.isEmpty())
			return ResourceManager.getMessage(EDITION_RIGHTS_EMPTY,
					locale);
		
		StringBuffer buf = new StringBuffer(ResourceManager.getMessage(
				EDITION_RIGHTS_LIST, locale));
		Iterator itStruct = rights.iterator();
		while(itStruct.hasNext()) {
			StructureLite struct = (StructureLite)itStruct.next();
			buf.append(struct.getFullName());
			if(itStruct.hasNext())
				buf.append(", ");
		}
		
		return buf.toString();
	}

	public String getStructuresSet() {
		return structuresSet;
	}

	public void setStructuresSet(String a_structuresSet) {
		structuresSet = a_structuresSet;
	}

	public Set getConsultationStructures() {
		return consultationStructures;
	}

	public void setConsultationStructures(Set a_consultationStructures) {
		consultationStructures = a_consultationStructures;
	}

	public Set getEditionStructures() {
		return editionStructures;
	}

	public void setEditionStructures(Set a_editionStructures) {
		editionStructures = a_editionStructures;
	}

	public String getEditionRights() {
		return editionRights;
	}

	public void setEditionRights(String a_editionRights) {
		editionRights = a_editionRights;
	}

	public boolean isCanSetRights() {
		return canSetRights;
	}

	public void setCanSetRights(boolean a_canSetRights) {
		canSetRights = a_canSetRights;
	}

  public boolean isLocked() {
    return isLocked;
  }

  public void setLocked(boolean isLocked) {
    this.isLocked = isLocked;
  }

  public String getLockTime() {
    return lockTime;
  }

  public void setLockTime(String lockTime) {
    this.lockTime = lockTime;
  }

	public EntryModel getSelectedModel() {
		return selectedModel;
	}

	public void setSelectedModel(EntryModel model) {
		selectedModel = model;
	}

	public Collection getSelectableModels() {
		return selectableModels;
	}

	public void setSelectableModels(Collection selectableModels) {
		this.selectableModels = selectableModels;
	}

	public boolean isManageFiles() {
		return manageFiles;
	}

	public void setManageFiles(boolean manageFiles) {
		this.manageFiles = manageFiles;
	}

	public Long getSelectedModelId() {
		return selectedModelId;
	}

	public void setSelectedModelId(Long selectedModelId) {
		this.selectedModelId = selectedModelId;
	}

	public TreeMap getPropertyValues() {
		return propValues;
	}

	public void setPropertyValues(TreeMap propValues) {
		this.propValues = propValues;
	}
}
